前言
之前归纳了databinding,说到底databinding也只是承载实体数据和UI进行关联,以及它们之间互通,转换。但是呢们开发过程中需要有中间人来控制逻辑,连接后台数据到绑定数据。这个时候ViewModel加上DataBinding以及LiveData就可以很好的组成一种架构模式。我们还是在了解LiveData和ViewModel之后,再结合之前的DataBinding来说MVVM吧。
LiveData
老规矩,首先附上官方文档地址:LiveData
看看官方怎么定义LiveData的:
LiveData是一个可观察对象持有类,不同于平常的可观察对象,LiveData是有生命周期感知的,意味着它会关心app组件的生命周期,比如Activity,fragment,service。这种感知特性保证LiveData只会在生命周期活跃的时候进行观察更新。
LiveData考虑将观察者,在生命周期为started
和resumed
下保持活跃。LiveData仅仅会通知活跃的观察者进行更新,不活跃的观察者不会收到任何通知。
你可以注册观察者并且给他配对实现了LifecycleOwner
的接口的对象。在这层关系下,观察者会在Lifecycle
对象进入destory
时被移除,这个对于fragment
和activity
非常有用,它可以很安全的观察livedata对象,在fragment
和activity
生命周期销毁时,它们会立即解除订阅,不会产生内存泄漏。
LiveData优点
确保UI和数据状态匹配
通过观察者模式,livedata会在生命周期发生改变通知观察者,通过书写固定更新UI代码,在数据发生改变时触发,而不是手动在数据改变时改变UI。
没有内存泄漏
观察者会被绑定到
Lifecycle
对象,在关联的生命周期被销毁时,观察者会被清理。activity停止不会崩溃
如果观察者处于不活跃状态,比如activity在后台运行,观察者不会收到livedata的事件
不需要手动管理生命周期
UI组件只会观察数据,不会停止和恢复观察,这些都是交由livedata自动管理。因为livedata可以感知
保持数据最新
如果生命周期是不活跃的,它将在变为活跃是获取最新的数据。例如activity从后台来到前台将会收取最新的数据。
适配配置更改
activity和fragment因为配置更改而重建,它们会收到最新的数据
共享资源
使用单例模式继承LiveData,并且包裹系统服务,以便能够在在全局使用,一旦连接到系统服务,任何观察者都可以查看livedata。
使用LiveData
一般来讲是要声明依赖
1 | dependencies { |
但是呢,我在AS3.4的基础上打开Databing后,这些LiveData和ViewModel都有了。。这些组件也是几年前就有了就,估计因为现在是9012年的原因,直接都给你集成好了。
一般来说是这样的步骤:
- 在ViewModel中声明创键LiveData对象
- 在UI控制器中,比如activity,fragment中创键观察者
Observer
对象,实现onChange
逻辑 - 通过在LiveData上调用
oberve
关联Observer
和LiveData
,需要传入lifecycleOwner
,一般是在UI控制中执行
如果oberver和livedata之间没有关联lifecycleOwner,则默认考虑这个observer总是处于活跃状态,即总是接受通知发生调用。你可以通过
removeOberver()
移除它
当livedata数据发生改变,将会触发附着在生命周期上活跃的oberver
livedata允许在控制器中订阅它,并且触发进行UI变化
创键LiveData对象
LiveData一个可以包装对象,包括了集合,一个LiveData通常是在ViewModel中声明的,同时提供getter方法。
1 | public class NameViewModel extends ViewModel { |
确保在ViewModel中存储UI的LiveData对象,第一,避免activity和fragment过度膨胀,它们的职责应该是负责UI显示而不是保存数据状态,第二、将LiveData实例和activity,fragment进行解耦,并且允许在配置发生改变时依然存活
观察LiveData对象
在大多数情况下,在app组件的onCreate
方法中开启LiveData
观察是非常适合的,原因如下:
- onResume调用时不会产生冗余调用在
- 确保activity,fragment拥有数据,在处于活跃状态立即展示它,一旦进入
started
状态,立即收取最近的数据
触发活跃状态下的oberver,例外,从非活跃转为活跃也会触发,如果第二次从非活跃到活跃,只有上次情况下的值发生改变了才会触发。
1 | public class NameActivity extends AppCompatActivity { |
数据改变,触发监听
更新LiveData对象
通过setValue(T)
和postValue
来更新数据,触发监听,更新UI
setValue
只能在主线程中更新数据
postValue
可以在子线程中,子线程中用它就对了
1 | button.setOnClickListener(new OnClickListener() { |
Room中使用LiveData
Room支持可观察的查询,返回LiveData对象,通过LiveData,以及设置观察者,保持UI数据和数据库同步,具体以后看Room的学习吧
LiveData使用协程
支持kotlin的协程(呃呃,这个我还不是很会😭)
扩展LiveData
LiveData会根据oberver生命周期宿主是否是STARTED
和RESUME
来认定oberver是否处于活跃和非活跃状态
1 | public class StockLiveData extends LiveData<BigDecimal> { |
- onActive 当LiveData拥有活跃的oberver,可以开始监听数据,调用
- onInActive LiveData没有活跃的oberver,不会触发监听,调用
通过扩展,可以加入自己的监听器
这些obsever会随着生命周期变化,比如活跃状态,消亡状态
通过单例进行分享
1 | public class StockLiveData extends LiveData<BigDecimal> { |
然后你可以在fragment使用
1 | public class MyFragment extends Fragment { |
变换LiveData
当你想要在发送通知前改变LiveData
的值,或者你需要基于原来的LiveData
返回一个另一LiveData
,LifeCycle
包里面提供了这样的工具类Transformations
map
1 | LiveData<User> userLiveData = ...; |
switchMap
1 | private LiveData<User> getUser(String id) { |
变换是惰性的,只有在在正处于观察和返回数据时进行计算。
合并多个LiveData源
MediatorLiveData
是一个包装了LiveData数据源集合的LiveData的,本质上是个包装类,也就是说完全可以当初LiveData使用,内部的话可以添加多个LiveData数据源,并且设置监听,一旦某数据源发生数据改变,可以触发监听,同时可以设置自身的数据,从而表现为一个LiveData。简单点说就是可以接受多个数据源,从而发生改变表现为一个数据源。
总结
总的来讲LiveData对象,就是一个具有生命周期感知的,持有可观察数据,不仅仅局限于UI。使用它可以在MVVM的结构中使得ViewModel不依赖View这一层从而完成View的变化。
View->ViewModel->Model
ViewModel
定义:在生命周期中,用于存储管理UI关联的数据。ViewModel允许在配置发生改变时存活
缘由:
Android framework管理者activity,fragment的生命周期,Android framework 也许会因为某些失控的事件和操作来进行销毁,重建activity,fragment。在发生这种情况下时候,瞬时的UI数据就会丢失,在之前的情况下我们会通过onSaveInstanceState
去保存某些数据,以便下次重建时onCreate
进行数据恢复,但是这个解决方式只适用于一些轻量的序列化数据,像那些Bitmap
就不适用了。
再者,UI控制器会经常性去做一些异步调用,并且有可能返回数据,为了防止内存泄漏,UI控制器需要管理这些调用,在UI控制器销毁时去清理。这种方式需要大量的维护,并且在配置发生改变,某些需要重建的资源对象在重建时会消耗大量资源。
对于UI控制器来说,它的责任应该是UI展示,UI交互,处理和系统的交流比如权限请求。将过多的责任分配给UI控制器会导致代码臃肿。尝试将一些责任分配出去,也会便于测试。
实现ViewModel
架构组件提供ViewModel来帮助UI控制器承担UI数据贮备的职责,并且它会在配置改变时自动保存,下次恢复时立马可用。
这个例子是用于加载用户列表数据
1 | public class MyViewModel extends ViewModel { |
在UI控制器中监听数据变化
1 | public class MyActivity extends AppCompatActivity { |
ViewModel不允许持有View引用、Lifecycle以及任何持有了activity context的对象的引用,即UI无关
生命周期
ViewModel的作用域是通过Lifecycle
通过ViewModelProvider
传递的,ViewModel
会保留在内存中,直到Lifecycle
的作用域消失,比如,activity的finish,fragment的detach,可以见下图
通常来讲实在第一次请求onCreate
创键ViewModel
,过程中可能多次onCreate
,但是在第一次请求ViewModel
直到activity finished and destroyed 之间都是存在的。
在Fragment间共享数据,通信
通常一个activity会包含多个fragment,然而多个fragment之间会涉及相关联的数据以及操作,fragment之间需要通信,简单的解决方法是通过定义接口进行回调,但是很繁琐,每个都写那不得烦死,还得绑定,解绑,生命周期可见性,各种考虑。通过共享得ViewModel可以很好的解决这个问题。
1 | public class SharedViewModel extends ViewModel { |
两个fragment共同处于一个activity,当然viewmodel也是同一个。
优点
- activity不需要了解任何事情,甚至通信内容
- fragment只需要了解和Viewmodel之间的契约,其它的不需要了解,其中之一的fragment消失了,另一个还是会正常工作
- 每个fragment都有各自的生命周期,它们之间互不影响,如果一个fragment被替换了,UI还是会正常工作。
使用ViewModel替换loader进行加载
以前使用loader来同步UI和数据库的数据
现在这样用
ViewModel中使用协程
待学习
总结
随着数据变得复杂,考虑将数据加载分离出去,当当当,这一步走完不就是MVVM了吗?哈哈
MVVM
其实从DataBind到LiveData,再到ViewModel就差不多是MVVM的雏形了
M:Model层,用于实际的数据加载,只负责加载数据
V:View层,负责UI展示,交互
VM:ViewMdoel层,负责View的数据,连通View和Model,负责获取Model的数据,转化为UI的数据,当然也包括了逻辑处理
如果感觉VM层太繁重,可以继续分离一层Presenter来处理逻辑,亦或者分离一层Mediator来处理验证
View -> ViewModel -> Model 现在的依赖单向,通过LiveData和双向绑定,ViewModel不需要依赖View了。
现在的架构变成这样了,简洁明了